﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.Prism.ViewModel;
using BBInterfaceNET.ProjectExplorer.Model;
using System.IO;
using System.Xml.Linq;
using Microsoft.Practices.Prism.Commands;
using BBInterfaceNET.ProjectExplorer.Commands;
using System.Windows;
using Microsoft.Win32;
using Microsoft.Practices.Prism.Events;
using ExplorerInfrastructure;
using ExplorerInfrastructure.Events;

namespace BBInterfaceNET.ProjectExplorer.ViewModels
{
    public class ExplorerViewModel:NotificationObject, IProjectExplorer
    {
        private IEventAggregator eventAggregator;
        private ProjectTree theTree;

        private DelegateCommand<ProjectNodeBase> addNewItem, addExistingItem, 
            addDirectory, openFile, deleteCmd, renameCmd;

        public ExplorerViewModel(IEventAggregator eventAggregator)
        {
            this.eventAggregator = eventAggregator;

            addNewItem = new DelegateCommand<ProjectNodeBase>(OnAddNewItemCommand);
            ExplorerCommands.NewFileCommand.RegisterCommand(addNewItem);

            addExistingItem = new DelegateCommand<ProjectNodeBase>(OnAddExistingItemCommand);
            ExplorerCommands.ExistingFileCommand.RegisterCommand(addExistingItem);

            addDirectory = new DelegateCommand<ProjectNodeBase>(OnAddDirectoryCommand);
            ExplorerCommands.NewDirectoryCommand.RegisterCommand(addDirectory);

            openFile = new DelegateCommand<ProjectNodeBase>(OnOpenFile);
            ExplorerCommands.OpenFileCommand.RegisterCommand(openFile);

            deleteCmd = new DelegateCommand<ProjectNodeBase>(OnDeleteItem);
            ExplorerCommands.DeleteCommand.RegisterCommand(deleteCmd);

            renameCmd = new DelegateCommand<ProjectNodeBase>(OnRenameItem);
            ExplorerCommands.RenameCommand.RegisterCommand(renameCmd);

        }

        #region properties
        public ProjectTree ProjectTree
        {
            get { return theTree; }
            private set
            {
                if (theTree != value)
                {
                    theTree = value;
                    RaisePropertyChanged(() => ProjectTree);
                }
            }
        }
        public string ProjectName
        {
            get
            {
                if (ProjectTree == null) return null;
                return ProjectTree.Nodes[0].Name;
            }
        }
        public string ProjectPath
        {
            get
            {
                if (ProjectTree == null) return null;
                return ProjectTree.Path;
            }
        }
        #endregion

        #region command properties
        public DelegateCommand<ProjectNodeBase> AddNewItemCommand
        {
            get { return addNewItem; }
        }
        public DelegateCommand<ProjectNodeBase> AddExistingItemCommand
        {
            get { return addExistingItem; }
        }
        public DelegateCommand<ProjectNodeBase> AddDirectoryCommand
        {
            get { return addDirectory; }
        }
        public DelegateCommand<ProjectNodeBase> DeleteCommand
        {
            get { return deleteCmd; }
        }
        public DelegateCommand<ProjectNodeBase> OpenFileCommand
        {
            get { return openFile; }
        }
        public DelegateCommand<ProjectNodeBase> RenameCommand
        {
            get { return renameCmd; }
        }
        #endregion

        private void OnAddDirectoryCommand(ProjectNodeBase currentNode)
        {
            //add a new directory
            if (currentNode == null || currentNode is FileNode)
                return;

            //check to see if you have an entry with the predefined dir name
            //if you don't, add it. if you do add one with increment
            string newPathBase = ProjectTree.Path;
            if (currentNode.Parent != null)
                newPathBase = Path.Combine(newPathBase, currentNode.GetPath().Substring(1));
            int i = 1;
            string newNodeName = "";
            do
            {
                newNodeName = "NewDirectory" + i;
                i++;
            }
            while (Directory.Exists(Path.Combine(newPathBase, newNodeName)));

            //create the tree entry
            string dir = newNodeName;
            DirectoryNode dItem = new DirectoryNode();
            dItem.Name = dir;
            currentNode.AddNode(dItem);
            //if the file is the first in the dir remove the dir entry and add the file 
            //entry instead
            //2 get the path of the dir
            string relPath = dItem.GetPath();
            string absPath = Path.Combine(theTree.Path, relPath.Substring(1));
            //3 create the dir on the drive (won't ask for overwrite)
            Directory.CreateDirectory(absPath);
            //4 write the dir in the project file
            string prjPath = Path.Combine(theTree.Path, theTree.Nodes[0].Name);
            XDocument doc = XDocument.Load(prjPath);
            //4.1 if the dir name for this directory is empty delete it

            string dirDir = Path.GetDirectoryName(relPath);
            XElement fEl = doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME).First().Descendants().Where(p => p.Attribute("name").Value.ToLower().Equals(dirDir.Substring(1).ToLower())).SingleOrDefault();
            if (fEl != null)
            {
                fEl.Remove();
            }
            //4.2 add the directory entry to the project file
            XElement xf = new XElement(ProjectFileConstants.FOLDER_ENTRY_NAME);
            xf.SetAttributeValue(ProjectFileConstants.NAME_ATTRIBUTE, relPath);
            doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME).First().Add(xf);

            using (FileStream fs = File.Open(prjPath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                fs.SetLength(0);
                using (StreamWriter sw = new StreamWriter(fs))
                {
                    doc.Save(sw);
                }
            }
        }

        private void OnAddNewItemCommand(ProjectNodeBase currentNode)
        {
            if (currentNode == null || currentNode is FileNode)
                return;

            //check to see if you have an entry with the predefined file name
            //if you don't, add it. if you do add one with increment
            string newPathBase = ProjectTree.Path;
            if(currentNode.Parent!=null)
                newPathBase = Path.Combine(newPathBase, currentNode.GetPath().Substring(1));
            int i = 1;
            string newNodeName = "";
            do
            {
                newNodeName = "NewFile" + i+ProjectFileConstants.FILE_EXTENSION;
                i++;
            }
            while (File.Exists(Path.Combine(newPathBase, newNodeName)));
            //create the tree entry
            FileNode dItem = new FileNode();
            dItem.Name = newNodeName;
            currentNode.AddNode(dItem);
            //create the file
            string relPath = dItem.GetPath();
            string absPath = Path.Combine(theTree.Path, relPath.Substring(1));
            //create the dir on the drive (won't ask for overwrite)
            using (Stream stream = File.Create(absPath))
            {}
       
            //write the file in the project file
            string prjPath = Path.Combine(theTree.Path, theTree.Nodes[0].Name);
            XDocument doc = XDocument.Load(prjPath);

            string fileDir = System.IO.Path.GetDirectoryName(dItem.GetPath());
            XElement filesEl = doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME).First();

            XElement fEl = filesEl.Descendants()
                .Where(p => p.Attribute(ProjectFileConstants.NAME_ATTRIBUTE).Value.ToLower().Equals(fileDir.ToLower())).SingleOrDefault();
            if (fEl != null)
            {
                fEl.Remove();
            }

            //4.construct the new file to add
            XElement file = new XElement(ProjectFileConstants.FILE_ENTRY_NAME);
            file.SetAttributeValue(ProjectFileConstants.NAME_ATTRIBUTE, dItem.GetPath());
            //5.add the new entry
            filesEl.Add(file);

            doc.Save(prjPath);
            //publish the event
            OnItemCreated(absPath);
        }

        private void OnAddExistingItemCommand(ProjectNodeBase currentNode)
        {
            //needs to be dir or proj node
            if (currentNode == null || currentNode is FileNode)
                return;
            //1. open a dialog and get the list of files you want to import
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "Designer Files (*.bbfx)|*.bbfx|Image Files (*.bmp;*.jpg;*.jpeg;*.png)|*.bmp;*.jpg;*.jpeg;*.png";
            dlg.Multiselect = true;
            bool? res = dlg.ShowDialog();
            if (res == null || !res.Value) return;
            string[] files = dlg.FileNames;
            //2. get the contents of the project file
            string projPath = Path.Combine(ProjectTree.Path, ProjectTree.Nodes[0].Name);
            XDocument doc = XDocument.Load(projPath);
            //3. if the current directory in the proj file is empty remove it from
            //the proj file. this hapens if the folder is empty
            string dirDir = currentNode.GetPath();
            if (currentNode.Parent != null)
            {
                XElement fEl = doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME)
                .First().Descendants().Where(p => p.Attribute(ProjectFileConstants.NAME_ATTRIBUTE)
                    .Value.ToLower().Equals(dirDir.ToLower()))
                .SingleOrDefault();
                if (fEl != null)
                {
                    fEl.Remove();
                }
            }
            string destPathBase = ProjectTree.Path;
            if (currentNode.Parent != null)
                destPathBase = Path.Combine(destPathBase, dirDir.Substring(1));

            List<string> addedFiles = new List<string>();
            //4. add each valid entry 
            foreach (string file in files)
            {
                string destPath = Path.Combine(destPathBase, Path.GetFileName(file));
                //if destination does not exist
                if (!File.Exists(destPath))
                {
                    //4.1 copy the file to dest
                    File.Copy(file, destPath);
                    bool isDestInProj = false;
                    string relPath = Path.Combine(currentNode.GetPath(), Path.GetFileName(destPath));
                    if (!relPath.StartsWith("\\")) relPath = "\\" + relPath;
                    isDestInProj = doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME).First()
                        .Descendants().Where(p => p.Attribute(ProjectFileConstants.NAME_ATTRIBUTE).Value.ToLower()
                            .Equals(relPath.ToLower())).Any();
                    if (!isDestInProj)
                    {
                        //4.2 create the tree entry
                        FileNode node = new FileNode();
                        node.Name = Path.GetFileName(file);
                        currentNode.AddNode(node);
                        //4.3 add the entry to the proj file
                        string path = node.GetPath();
                        XElement el = new XElement(ProjectFileConstants.FILE_ENTRY_NAME, new XAttribute(ProjectFileConstants.NAME_ATTRIBUTE, path));
                        XElement root = doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME).First();
                        root.Add(el);
                        addedFiles.Add(destPath);
                    }
                    else
                    {//is in proj
                        //get the node and update the icon state from not found to normal
                    }

                }
                else if (file.ToLower().Equals(destPath.ToLower()))
                {//the file is in the proj dir
                    bool isDestInProj = false;
                    string relPath = Path.Combine(currentNode.GetPath(), Path.GetFileName(destPath));
                    if (!relPath.StartsWith("\\")) relPath = "\\" + relPath;
                    isDestInProj = doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME).First()
                        .Descendants().Where(p => p.Attribute(ProjectFileConstants.NAME_ATTRIBUTE).Value.ToLower()
                            .Equals(relPath.ToLower())).Any();
                    if (!isDestInProj)
                    {
                        FileNode node = new FileNode();
                        node.Name = Path.GetFileName(file);
                        currentNode.AddNode(node);
                        //4.3 add the entry to the proj file
                        string path = node.GetPath();
                        XElement el = new XElement(ProjectFileConstants.FILE_ENTRY_NAME, new XAttribute(ProjectFileConstants.NAME_ATTRIBUTE, path));
                        XElement root = doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME).First();
                        root.Add(el);
                        addedFiles.Add(destPath);
                    }
                }
                else if (!file.ToLower().Equals(destPath.ToLower()))
                {
                    //overwrite?
                    MessageBoxResult res2 = MessageBox.Show("Do you want to overwrite?", "File Exists", MessageBoxButton.YesNo);
                    if (res2 == MessageBoxResult.No) continue;
                    //replace file
                    File.Delete(destPath);
                    File.Copy(file, destPath);
                    //if not in proj => add to proj
                    string relPath = Path.Combine(currentNode.GetPath(), Path.GetFileName(destPath));
                    if (!relPath.StartsWith("\\")) relPath = "\\" + relPath;
                    bool isInProj = doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME).First()
                        .Descendants().Where(p => p.Attribute(ProjectFileConstants.NAME_ATTRIBUTE).Value.ToLower()
                            .Equals(relPath.ToLower())).Any();
                    if (!isInProj)
                    {
                        FileNode node = new FileNode();
                        node.Name = Path.GetFileName(file);
                        currentNode.AddNode(node);
                        //4.3 add the entry to the proj file
                        string path = node.GetPath();
                        XElement el = new XElement(ProjectFileConstants.FILE_ENTRY_NAME, new XAttribute(ProjectFileConstants.NAME_ATTRIBUTE, path));
                        XElement root = doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME).First();
                        root.Add(el);
                        addedFiles.Add(destPath);
                    }
                    else
                    {
                        //NOTIFY Modules
                    }
                }
            }
            //5. save the proj file
            doc.Save(projPath);
            for (int i = 0; i < addedFiles.Count; i++)
                OnItemAdded(addedFiles[i]);
        }

        private void OnDeleteItem(ProjectNodeBase currentNode)
        {
            if (currentNode == null) return;

            MessageBoxResult res = MessageBox.Show("Do you want to delete this item?", "Delete", MessageBoxButton.YesNo);
            if (res != MessageBoxResult.Yes) return;

            //delete from disk
            string relPath = currentNode.GetPath().Substring(1);
            string absPath = Path.Combine(ProjectTree.Path, relPath);

            if (currentNode is DirectoryNode && Directory.Exists(absPath))
                Directory.Delete(absPath, true);
            else if(File.Exists(absPath))
                File.Delete(absPath);


            //delete from project
            //remove any entry from the project file that starts with the relPath
            string absProjPath = Path.Combine(ProjectTree.Path, ProjectTree.Nodes[0].Name);
            XElement doc = XElement.Load(absProjPath);
            List<XElement> fElems = doc.Descendants(ProjectFileConstants.FILES_CONTAINER_NAME).First().Descendants()
                .Where(p => p.Attribute(ProjectFileConstants.NAME_ATTRIBUTE).Value.ToLower()
                    .Contains(relPath.ToLower()))
                .ToList();
            //the list of files that will be published
            List<string> delFiles = new List<string>();
            foreach (XElement elem in fElems)
            {
                string rPath = elem.Attribute(ProjectFileConstants.NAME_ATTRIBUTE).Value;
                string path = Path.Combine(ProjectTree.Path, rPath.Substring(1));
                elem.Remove();
                if (elem.Name.LocalName.ToLower().Equals(ProjectFileConstants.FILE_ENTRY_NAME))
                {
                    delFiles.Add(path);
                }
            }

            //if i deleted the last child in the dir add the parent path (the dir path)
            ProjectNodeBase parent = currentNode.Parent;
            if (parent.Children.Count == 1 && !(parent is ProjectNode))
            {
                XElement pEl = new XElement(ProjectFileConstants.FOLDER_ENTRY_NAME);
                pEl.SetAttributeValue(ProjectFileConstants.NAME_ATTRIBUTE, parent.GetPath());
                doc.Element(ProjectFileConstants.FILES_CONTAINER_NAME).Add(pEl);
            }
            //save the modified project file
            using (FileStream fs = File.Open(absProjPath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                fs.SetLength(0);
                using (StreamWriter sw = new StreamWriter(fs))
                {
                    doc.Save(sw);
                }
            }
            //delete from tree
            currentNode.Parent.Children.Remove(currentNode);
            //signal the deletion
            for (int i = 0; i < delFiles.Count; i++)
                OnItemDeleted(delFiles[i]);
        }

        private void OnOpenFile(ProjectNodeBase currentNode)
        {
            //signal to open
            string path = Path.Combine(ProjectTree.Path, currentNode.GetPath().Substring(1));
            OnItemOpened(path);
        }

        private void OnRenameItem(ProjectNodeBase currentNode)
        {
            currentNode.Editing = true;
        }

        public void RenameItem(ProjectNodeBase currentNode, string oldName)
        {
            string currExt = Path.GetExtension(currentNode.Name.ToLower());

            if (currentNode is FileNode && string.IsNullOrEmpty(currExt))
            {
                string withoutExt = Path.GetFileNameWithoutExtension(currentNode.Name);
                string oldExt = Path.GetExtension(oldName);
                //make sure the extension is right. if not rename the file
                currentNode.Name =  withoutExt+oldExt;
            }
            string newAbsPath = Path.Combine(ProjectTree.Path, currentNode.GetPath().Substring(1));

            //see if there are sibling nodes with the same name.
            //if they are don't make the change.
            if ((currentNode is FileNode && File.Exists(newAbsPath)) ||
                (currentNode is DirectoryNode && Directory.Exists(newAbsPath)))
            {
                if (currentNode.Name.ToLower().Equals(oldName.ToLower()))
                {
                    currentNode.Editing = false;
                }
                else
                {
                    MessageBox.Show("A file or folder with the specified name already exists on disk. Please choose another name.");
                    currentNode.Name = oldName;
                }
                return;
            }
            currentNode.Editing = false;
            //2.1 get the new file path
            string newPath = currentNode.GetPath();
            //2.2 get the old file path                
            //make sure the text gets replaced only once
            string oldPath = newPath.Remove(newPath.LastIndexOf(currentNode.Name));
            oldPath = oldPath + oldName;
            //2.3 replace the old path with the new one in the proj file
            string projFilePath = System.IO.Path.Combine(ProjectTree.Path, ProjectTree.Nodes[0].Name);
            XElement el = XElement.Load(projFilePath);
            var elms = el.Element(ProjectFileConstants.FILES_CONTAINER_NAME).Descendants().Where(p => p.Attribute(ProjectFileConstants.NAME_ATTRIBUTE).Value.ToLower().StartsWith(oldPath.ToLower()));
            //the renamed file collection that will be published
            var renamedFiles = new List<Tuple<string, string>>();
            //iterate over each entry in the project file that starts with the old path
            //this ensures that both directories and files will be renamed
            foreach (XElement elm in elms)
            {
                String old = elm.Attribute(ProjectFileConstants.NAME_ATTRIBUTE).Value;
                String ren = old;
                if(ren.ToLower().StartsWith(oldPath.ToLower())){
                    ren=ren.Substring(oldPath.Length);
                    ren = newPath + ren;
                }
                elm.SetAttributeValue(ProjectFileConstants.NAME_ATTRIBUTE, ren);
                //if the evement is a file add it to the list
                if (elm.Name.LocalName.Equals(ProjectFileConstants.FILE_ENTRY_NAME))
                {
                    
                    string nextPath = Path.Combine(ProjectTree.Path, ren.Substring(1));
                    string prevPath = Path.Combine(ProjectTree.Path, old.Substring(1));

                    Tuple<string, string> item = new Tuple<string, string>(nextPath, prevPath);

                    renamedFiles.Add(item);
                }
            }
            using (FileStream fs = File.Open(projFilePath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                fs.SetLength(0);
                using (StreamWriter sw = new StreamWriter(fs))
                {
                    el.Save(sw);
                }
            }
            //2.4 find the file based on the old path and rename it
            string oldDir = System.IO.Path.Combine(ProjectTree.Path, oldPath.Substring(1));

            //2.5 make the disk changes
            if (currentNode is DirectoryNode)
            {
                if (Directory.Exists(oldDir) && !Directory.Exists(newAbsPath) && !oldDir.ToLower().Equals(newAbsPath.ToLower()))
                {
                    Directory.Move(oldDir, newAbsPath);
                }
            }
            else if (currentNode is FileNode)
            {
                if (File.Exists(oldDir) && !File.Exists(newAbsPath) && !oldDir.ToLower().Equals(newAbsPath.ToLower()))
                {
                    File.Move(oldDir, newAbsPath);
                }
            }
            //publish the renamed event
            for (int i = 0; i < renamedFiles.Count; i++)
            {
                OnItemRenamed(renamedFiles[i].Item2, renamedFiles[i].Item1);
            }
        }
        
        //create a project.
        public void CreateNewProject(ProjectInfo info)
        {
            if (File.Exists(info.Path))
            {
                throw new Exception("A file with the specified name already exists at the specified location. Choose another.");
            }
            if (!Path.GetExtension(info.Path).ToLower().Equals(ProjectFileConstants.PROJECT_EXTENSION))
            {
                throw new Exception("Incorrect project file extension");
            }

            CloseProject();
            //store the project on disk
            string dir = Path.GetDirectoryName(info.Path);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            XElement el = new XElement(ProjectFileConstants.ROOT_NAME, new XElement(ProjectFileConstants.FILES_CONTAINER_NAME));
            el.SetAttributeValue(ProjectFileConstants.OS_VER_ATTR, info.OsVersion);
            el.SetAttributeValue(ProjectFileConstants.FONT_SIZE_ATTR, info.FontSize);
            el.SetAttributeValue(ProjectFileConstants.SCREEN_WIDTH_ATTR, info.ScreenSize.Width);
            el.SetAttributeValue(ProjectFileConstants.SCREEN_HEIGHT_ATTR, info.ScreenSize.Height);
            XDocument doc = new XDocument(el);
            //save the basic xml
            using (FileStream fs = File.Open(info.Path, FileMode.OpenOrCreate, FileAccess.Write))
            {
                doc.Save(fs);
            }

            //build the tree
            ProjectTree tree = new Model.ProjectTree();
            ProjectNode root = new ProjectNode();
            root.Name = Path.GetFileName(info.Path);
            tree.Nodes.Add(root);
            tree.Path = dir;
            ProjectTree = tree;
        }

        public void CloseProject()
        {
            if (!IsOpened())
                return;
            //clear the data
            string path=ProjectTree.Path;
            string projName = ProjectTree.Nodes[0].Name;
            ProjectTree = null;
            //notify
            OnProjectClosed(Path.Combine(path, projName));
        }
        
        public bool IsOpened()
        {
            return ProjectTree != null;
        }

        public ProjectInfo OpenProject(string projPath)
        {
            //check if file exists
            if (!(File.Exists(projPath) && Path.GetExtension(projPath)
                .ToLower().Equals(ProjectFileConstants.PROJECT_EXTENSION)))
                return null;
            //close existing project
            CloseProject();
            //build new project
            string path = Path.GetDirectoryName(projPath);
            string name = Path.GetFileName(projPath);

            ProjectTree tree = new Model.ProjectTree();            
            ProjectNode projNode = new ProjectNode();
            projNode.Name = name;
            tree.Path = path;
            tree.Nodes.Add(projNode);
            ProjectTree = tree;

            ProjectInfo pi = ProjectInfo.GetInstance();
            try
            {
                //load project from file
                XDocument xdoc = XDocument.Load(projPath);
                XElement el = xdoc.Descendants(ProjectFileConstants.ROOT_NAME).SingleOrDefault();
                if (el != null)
                {
                    pi.OsVersion = el.Attribute(ProjectFileConstants.OS_VER_ATTR).Value;
                    pi.FontSize = (int)el.Attribute(ProjectFileConstants.FONT_SIZE_ATTR);
                    int w = (int)el.Attribute(ProjectFileConstants.SCREEN_WIDTH_ATTR);
                    int h = (int)el.Attribute(ProjectFileConstants.SCREEN_HEIGHT_ATTR);
                    pi.ScreenSize = new Size(w, h);
                    pi.Path = projPath;
                }

                var files = xdoc.Descendants("files").First().Descendants()
                    .Select(p => new { Name = p.Attribute("name").Value, IsDir = (p.Name == "folder" ? true : false) }).ToList();
                //no entries. return
                if (!files.Any())
                    return pi;
                //iterate the entries
                foreach (var item in files)
                {
                    //2 split the file
                    string[] parts = item.Name.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries);
                    for (int j = 0; j < parts.Length; j++)
                    {
                        //3 for each part check the level and get the tree nodes at 
                        //the same level

                        if (j == 0)
                        {
                            //get the corresponding node. if it doesn't exist 
                            //create and add it.
                            var node = projNode.Children.Where(p => p.Name.ToLower().Equals(parts[j].ToLower()));
                            if (!node.Any())
                            {
                                ProjectNodeBase n;
                                if (j == parts.Length - 1 && item.IsDir == false)
                                {
                                    n = new FileNode();
                                    n.Name = parts[j];
                                }
                                else
                                {
                                    n = new DirectoryNode();
                                    n.Name = parts[j];
                                }
                                ProjectTree.AddNode(projNode, n);
                            }
                        }
                        else
                        {
                            //file inside directory
                            //check if the file exists
                            List<ProjectNodeBase> nodes = new List<ProjectNodeBase>();
                            ProjectTree.GetNodes(j, nodes);
                            var fileExists = nodes.Where(p => p.Name.ToLower().Equals(parts[j].ToLower()));
                            if (!fileExists.Any())
                            {
                                //is the file does not exist
                                //get previous part and nodes from previous level
                                string prevPart = parts[j - 1];
                                nodes = new List<ProjectNodeBase>();
                                ProjectTree.GetNodes(j - 1, nodes);
                                //get the correct previous node
                                var node = nodes.Where(p => p.Name.ToLower().Equals(prevPart.ToLower())).First();
                                //add the file

                                ProjectNodeBase n;
                                if (j == parts.Length - 1 && item.IsDir == false)
                                {
                                    n = new FileNode();
                                    n.Name = parts[j];
                                }
                                else
                                {
                                    n = new DirectoryNode();
                                    n.Name = parts[j];
                                }
                                ProjectTree.AddNode(node, n);
                            }
                        }

                    }//end of part loop
                }//end of global for loop
            }
            catch(Exception ex)
            {
                ProjectTree = null;
                throw ex;
            }
            return pi;
        }


        #region events
        public event EventHandler<FileEventArgs> ItemCreated;
        public event EventHandler<FileEventArgs> ItemAdded;
        public event EventHandler<FileEventArgs> ItemOpened;
        public event EventHandler<FileEventArgs> ItemDeleted;
        public event EventHandler<FileRenamedEventArgs> ItemRenamed;
        public event EventHandler<FileEventArgs> ProjectClosed;

        protected void OnItemCreated(string itemPath)
        {
            if (ItemCreated != null)
                ItemCreated(this, new FileEventArgs(itemPath));
        }
        protected void OnItemAdded(string itemPath)
        {
            if (ItemAdded != null)
                ItemAdded(this, new FileEventArgs(itemPath));
        }
        protected void OnItemOpened(string itemPath)
        {
            if (ItemOpened != null)
                ItemOpened(this, new FileEventArgs(itemPath));
        }
        protected void OnItemDeleted(string itemPath)
        {
            if (ItemDeleted != null)
                ItemDeleted(this, new FileEventArgs(itemPath));
        }
        protected void OnItemRenamed(string oldPath, string newPath)
        {
            if (ItemRenamed != null)
                ItemRenamed(this, new FileRenamedEventArgs(oldPath, newPath));
        }
        protected void OnProjectClosed(string projPath)
        {
            if (ProjectClosed != null)
                ProjectClosed(this, new FileEventArgs(projPath));
        }
        #endregion
    }
}
